import { MessageService } from './../message.service';
import { Hero } from './hero';
import { Injectable } from '@angular/core';
import { Observable, of, tap } from 'rxjs';
import { HttpClient,HttpHeaders } from '@angular/common/http';
import { catchError, map } from 'rxjs';

// 是为了注册成为一个服务提供者，因为只有服务提供者才可以添加至根应用的服务中
@Injectable({
  providedIn: 'root'
})
export class HeroService {

  private heroesUrl = 'api/heroes';  // URL to web api

  httpOptions = {
     headers: new HttpHeaders({'Content-Type': 'application/json'})
  }

  getHeroes(): Observable<Hero[]> {
      // of 可以将HEROES转化为Observable对象
      // const heroes = of(HEROES)
      // this.messageService.add('HeroService：fetched heroes')
      return this.http.get<Hero[]>(this.heroesUrl)
             .pipe(
              // tap(窥视)能窥探Obervable数据流，并用log打印，提醒数据以获取到
              tap(_ => this.log('fetched heroes')),
              catchError(this.handleError<Hero[]>('getHeroes',[]))
              )
  }

  /**
   * catchError会把出错的Observable对象交给handError来处理
   * 第一个参数是出错的函数的名字，一般传入当前方法，第二个是返回的结果
   *  */
  private handleError<T> (operation = 'operation', result?: T){
       return (error: any): Observable<T> => {

          //打印错误
          console.error(error)

          //写入日志
          this.log(`${operation} failed：${error.message}` )

          //返回一个安全的结果，保证正常运行，这里是返回一个空数组(从调用处可知)
          return of(result as T)
       }
  }

  getHero(id: number): Observable<Hero>{
     // of 可以将HEROES转化为Observable对象
    //  const hero = HEROES.find(h => h.id === id)!
    //  this.messageService.add(`HeroService：fetched hero id = ${id}`)
    //  return of(hero)
    const url =  `${this.heroesUrl}/${id}`
    return this.http.get<Hero>(url).pipe(
       tap(_ => this.log(`fethed hero id = ${id}`)),
       catchError(this.handleError<Hero>(`getHero id = ${id}`))
    )
  }

  // 没有返回值因此是any
  updateHero(hero: Hero): Observable<any>{
      // 在更新服务器数据时，需要一个请求头，不让浏览器认为是爬虫，可以认为是一个反爬虫机制
      return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
      tap(_ => this.log(`fethed hero id = ${hero.id}`)),
      catchError(this.handleError<any>('updateHero'))
   )
 }

 addHero(hero: Hero): Observable<Hero>{
    return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions)
    .pipe(
      tap((newHero:Hero) => this.log(`add hero w/ id = ${newHero.id}`)),
      catchError(this.handleError<Hero>('addHero'))
    )
 }

 deleteHero(hero: Hero): Observable<Hero>{
    const url = `${this.heroesUrl}/${hero.id}`
    return this.http.delete<Hero>(url,this.httpOptions).pipe(
      tap(_ => this.log(`deleted hero id = ${hero.id}`)),
      catchError(this.handleError<Hero>('deleteHero'))
    )
 }

  /** GET hero by id. Return `undefined` when id not found */


 //根据id请求英雄数据，若没有会返回404
 searchHeroes(term: string): Observable<Hero[]>{
    if(!term.trim()) {
      return of([]);
    }
    // 直接通过get的?name=xxx便可查询所有name为xxx的英雄
    // 这里name=${term}多一个空格都不行，就像是sql语句一样，而且这个竟然是模糊查询
    return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
       tap( x => x.length ?
          this.log(`found heroes matching "${term}"`) :
          this.log(`no heroes matching "${term}"`)),
       catchError(this.handleError<Hero[]>('searchHeroes',[]))
    );
 }

  private log(message: string){
     this.messageService.add(`HeroService：${message}`)
  }

  // 服务中注入服务
  constructor(private messageService: MessageService,private http: HttpClient) { }
}
